/*
 * Copyright 2005-2013 rsico. All rights reserved.
 * Support: http://www.rsico.cn
 * License: http://www.rsico.cn/license
 */
package com.rzico.core.plugin.alipay;

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.CertAlipayRequest;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.rzico.core.entity.SysPlugin;
import com.rzico.core.entity.SysUser;
import com.rzico.core.model.PluginAttribute;
import com.rzico.core.plugin.PaymentPlugin;
import com.rzico.util.IPUtils;
import com.rzico.util.MD5Utils;
import com.rzico.util.StringUtils;
import com.rzico.util.XMLUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.HttpClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedInputStream;
import java.io.InputStream;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.*;

/**
 * Plugin - 支付宝(普通商户/特约商户)
 * @author rsico Team
 * @version 3.0
 */
@Component("alipayAppPlugin")
@Slf4j
public class AlipayAppPlugin extends PaymentPlugin {

	public static final String UNIFIED_ORDER_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
	public static final String REFUNDS_ORDER_URL = "https://api.mch.weixin.qq.com/secapi/pay/refund";

	@Value("${weixin.appid}")
	private String wx_appid;
	@Value("${weixin.mchid}")
	private String wx_mchid;
	@Value("${weixin.mchSecret}")
	private String wx_mch_secret;
	@Value("${setting.host}")
	private String host;

	@Override
	public String getName() {
		return "支付宝(APP)";
	}

	@Override
	public String getVersion() {
		return "1.0";
	}

	@Override
	public List<PluginAttribute> getAttributeKeys() {
		List<PluginAttribute> data = new ArrayList<>();
		data.add(new PluginAttribute("method","商户类型",PluginAttribute.ARRAY_VALUE,"1.普通商户,2.特约商户"));
		data.add(new PluginAttribute("appid","appid",PluginAttribute.STRING_VALUE));
		data.add(new PluginAttribute("mchid","商户号",PluginAttribute.STRING_VALUE));
		data.add(new PluginAttribute("key","支付密钥(普通商户必填)",PluginAttribute.STRING_VALUE,null,false));
		data.add(new PluginAttribute("APP_PRIVATE_KEY","私钥",PluginAttribute.STRING_VALUE,null,false));
		data.add(new PluginAttribute("ALIPAY_PUBLIC_KEY","公钥",PluginAttribute.STRING_VALUE,null,false));
		return data;
	}

	/**
	 * 作用：生成签名
	 */
	public String getSign(HashMap<String, Object> params, SysPlugin sysPlugin) throws Exception {
		String str = joinKeyValue(params,"&",true,"sign","key");
		// 签名步骤二：在string后加入KEY
		if ("1".equals(sysPlugin.getAttribute("method"))) {
			str += "&key=" + sysPlugin.getAttribute("key");
		} else {
			str += "&key=" + wx_mch_secret;
		}
		// 签名步骤三：MD5加密 签名步骤四：所有字符转为大写
		str = MD5Utils.getMD5Str(str).toUpperCase();
		return str;
	}

	/**
	 * 获取用户号
	 * @param sysUser SysUser
	 * @return 获取用户号
	 */
	@Override
	public String getUserId(SysUser sysUser) {
		return sysUser.getWxmId();
	}

	@Override
	public Map<String, Object> trade(SysPlugin sysPlugin,String tradeNo, String description, BigDecimal totalfee, String userId, HttpServletRequest request) {

		//实例化客户端
		AlipayClient alipayClient = new DefaultAlipayClient(
				"https://openapi.alipay.com/gateway.do",
				sysPlugin.getAttribute("appid"),
				sysPlugin.getAttribute("APP_PRIVATE_KEY"),
				  "json",
				 "UTF-8",
				sysPlugin.getAttribute("ALIPAY_PUBLIC_KEY"),
				"RSA2"
		);

        //实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称：alipay.trade.app.pay
		AlipayTradeAppPayRequest req = new AlipayTradeAppPayRequest();
        //SDK已经封装掉了公共参数，这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
		AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();

		model.setSubject("我是测试数据");
		if (description.length()>40) {
			model.setBody(description.substring(0, 40));
		} else {
			model.setBody(description);
		}

		model.setOutTradeNo(tradeNo);
		model.setTimeoutExpress("30m");

		model.setTotalAmount(totalfee.setScale(2, BigDecimal.ROUND_HALF_UP).toString());
		model.setProductCode("QUICK_MSECURITY_PAY");
		req.setBizModel(model);
		req.setNotifyUrl(getNotifyUrl(sysPlugin));

		try {

			//这里和普通的接口调用不同，使用的是sdkExecute
			AlipayTradeAppPayResponse response = alipayClient.sdkExecute(req);

			System.out.println(response.getBody());//就是orderString 可以直接给客户端请求，无需再做处理。

		} catch (AlipayApiException e) {
			e.printStackTrace();
		}
        return null;


	}

	@Override
	public Map<String, Object> verifyNotify(SysPlugin sysPlugin,HttpServletRequest request) {
		HashMap<String, Object> finalpackage = new HashMap<>();
		try {
			HashMap<String, Object> resultMap = new HashMap<String, Object>();
			StringBuffer info = new StringBuffer();
			InputStream in = request.getInputStream();
			BufferedInputStream buf = new BufferedInputStream(in);
			byte[] buffer = new byte[1024];
			int iRead;
			while ((iRead = buf.read(buffer)) != -1) {
				info.append(new String(buffer, 0, iRead, "UTF-8"));
			}
			resultMap = XMLUtils.xmlToMap(info.toString());
			log.info("异常通知:"+info.toString());
			if (resultMap.get("result_code").toString().equals("SUCCESS")) {
				String sign = getSign(resultMap,sysPlugin);
				if (sign.equals(resultMap.get("sign").toString())) {
					finalpackage.put("return_code", "0000");
					finalpackage.put("tradeNo", (String) resultMap.get("out_trade_no"));
					finalpackage.put("tranSn", (String) resultMap.get("transaction_id"));
					return finalpackage;
				}
			}
			finalpackage.put("return_code", "9999");
			finalpackage.put("error_msg",(String) resultMap.get("return_msg"));
		} catch (Exception e) {
			finalpackage.put("return_code", "9999");
			finalpackage.put("error_msg", e.getMessage());
		}
		return finalpackage;
	}

	/**
	 * 查询订单的支付结果  0000成功  9999处理中  其他的失败
	 */
	@Override
	public Map<String, Object> tradeQuery(SysPlugin sysPlugin,String tradeNo,String tranSn,HttpServletRequest request) {

		HashMap<String, Object> finalpackage = new HashMap<>();
		String createNoncestr = StringUtils.CreateNoncestr();
		HashMap<String, Object> parameterMap = new HashMap<String, Object>();
		if ("1".equals(sysPlugin.getAttribute("method"))) {
			parameterMap.put("appid", sysPlugin.getAttribute("appid"));
			parameterMap.put("mch_id", sysPlugin.getAttribute("mchid"));
		} else {
			parameterMap.put("appid", wx_appid);
			parameterMap.put("mch_id", wx_mchid);
			parameterMap.put("sub_appid", sysPlugin.getAttribute("appid"));
			parameterMap.put("sub_mch_id", sysPlugin.getAttribute("mchid"));
		}
		parameterMap.put("out_trade_no",tradeNo);
		parameterMap.put("nonce_str", createNoncestr);
		try {
			parameterMap.put("sign",getSign(parameterMap,sysPlugin));
		} catch (Exception e) {
			finalpackage.put("return_code", "0003");
			finalpackage.put("error_msg","签名出错");
			return finalpackage;
		}

		try {
			String xml = XMLUtils.mapToXml(parameterMap);
			String resultXml = post("https://api.mch.weixin.qq.com/pay/orderquery",xml,null);
			Map<String,Object> resultMap = XMLUtils.xmlToMap(resultXml);
			String return_code = (String) resultMap.get("return_code");
			if (return_code.equals("SUCCESS")) {
				String result = (String) resultMap.get("result_code");
				if ("SUCCESS".equals(result)) {
					String status = (String) resultMap.get("trade_state");
					if (status.equals("SUCCESS")) {
						finalpackage.put("tranSn", (String) resultMap.get("transaction_id"));
						finalpackage.put("return_code", "0000");
						finalpackage.put("error_msg","支付成功");
					} else if (status.equals("REFUND")) {
						finalpackage.put("return_code", "0002");
						finalpackage.put("error_msg","转入退款");
					} else if (status.equals("REVOKED")) {
						finalpackage.put("return_code", "0002");
						finalpackage.put("error_msg","已撤消");
					} else if (status.equals("USERPAYING")) {
						finalpackage.put("return_code", "0001");
						finalpackage.put("error_msg","正在付款");
					} else if (status.equals("PAYERROR")) {
						finalpackage.put("return_code", "9999");
						finalpackage.put("error_msg","未知错误");
					} else {
						finalpackage.put("return_code", "0003");
						finalpackage.put("error_msg", (String) resultMap.get("err_code_des"));
					}
				} else  {
					String errCode = (String) resultMap.get("err_code");
					if ("ORDERNOTEXIST".equals(errCode)) {
						finalpackage.put("return_code", "0003");
						finalpackage.put("error_msg", (String) resultMap.get("err_code_des"));
					} else {
						finalpackage.put("return_code", "9999");
						finalpackage.put("error_msg", (String) resultMap.get("err_code_des"));
					}
				}
			} else
			{
				finalpackage.put("return_code", "9999");
				finalpackage.put("error_msg", (String) resultMap.get("return_msg"));
			}
		} catch (Exception e) {
			finalpackage.put("return_code", "9999");
			finalpackage.put("error_msg", "设置异常");
		}

		return finalpackage;
	}

	@Override
	public String getNotifyMessage(HttpServletRequest request) {
		return "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
	}

	/**
	 * 申请退款
	 */
	@Override
	public Map<String, Object> refund(SysPlugin sysPlugin, String refundNo, String tradeNo, BigDecimal totalfee, BigDecimal refundfee , HttpServletRequest request) {
		HashMap<String, Object> finalpackage = new HashMap<String, Object>();
		HashMap<String, Object> paramsMap = new HashMap<String, Object>();
		DecimalFormat decimalFormat = new DecimalFormat("#");
		if ("1".equals(sysPlugin.getAttribute("method"))) {
			paramsMap.put("appid", sysPlugin.getAttribute("appid"));
			paramsMap.put("mch_id", sysPlugin.getAttribute("mchid"));
		} else {
			paramsMap.put("appid", wx_appid);
			paramsMap.put("mch_id", wx_mchid);
			paramsMap.put("sub_appid", sysPlugin.getAttribute("appid"));
			paramsMap.put("sub_mch_id", sysPlugin.getAttribute("mchid"));
		}
		paramsMap.put("nonce_str", String.valueOf(new Date().getTime()));
		paramsMap.put("out_trade_no",tradeNo);
		paramsMap.put("out_refund_no",refundNo);
		paramsMap.put("total_fee", decimalFormat.format(totalfee.multiply(new BigDecimal(100))));
		paramsMap.put("refund_fee", decimalFormat.format(refundfee.multiply(new BigDecimal(100))));
		try {
			paramsMap.put("sign",getSign(paramsMap,sysPlugin));
		} catch (Exception e) {
			finalpackage.put("return_code", "0003");
			finalpackage.put("error_msg","签名出错");
			return finalpackage;
		}

		String reqUrl = "https://api.mch.weixin.qq.com/secapi/pay/refund";

		try {
			String xml = XMLUtils.mapToXml(paramsMap);
			HttpClient httpClient =	createSSLHttpClient(sysPlugin);
			String resultXml = post(reqUrl,xml,httpClient);
			HashMap<String,Object> resultMap = XMLUtils.xmlToMap(resultXml);
			if(resultMap.containsKey("sign")){
				String sign = getSign(resultMap,sysPlugin);
				if(!sign.equals(resultMap.get("sign"))){
					finalpackage.put("return_code", "0003");
					finalpackage.put("error_msg", "验证签名不通过");
					return finalpackage;
				}else{
					if("SUCCESS".equals(resultMap.get("return_code").toString()) && "SUCCESS".equals(resultMap.get("result_code").toString())){
						finalpackage.put("return_code", "0000");
						finalpackage.put("error_msg", "提交成功");
						finalpackage.put("tranSn", (String) resultMap.get("transaction_id"));
						return finalpackage;
					}else{
						finalpackage.put("return_code", "0003");
						finalpackage.put("error_msg", resultMap.get("err_code_des").toString());
						return finalpackage;
					}
				}
			}else{

				finalpackage.put("return_code", "0003");
				finalpackage.put("error_msg", resultMap.get("return_msg").toString());
				return finalpackage;
			}
		} catch (Exception e) {
			log.error(e.getMessage());
			finalpackage.put("return_code", "0003");
			finalpackage.put("error_msg","提交银行出错");
			return finalpackage;
		}


	}

	/**
	 * 查询退款
	 */
	@Override
	public Map<String, Object> refundQuery(SysPlugin sysPlugin, String tradeNo,String tranSn, HttpServletRequest request) {
		HashMap<String, Object> paramsMap = new HashMap<String, Object>();
		HashMap<String, Object> finalpackage = new HashMap<String, Object>();
		if ("1".equals(sysPlugin.getAttribute("method"))) {
			paramsMap.put("appid", sysPlugin.getAttribute("appid"));
			paramsMap.put("mch_id", sysPlugin.getAttribute("mchid"));
		} else {
			paramsMap.put("appid", wx_appid);
			paramsMap.put("mch_id", wx_mchid);
			paramsMap.put("sub_appid", sysPlugin.getAttribute("appid"));
			paramsMap.put("sub_mch_id", sysPlugin.getAttribute("mchid"));
		}
		paramsMap.put("out_refund_no",tradeNo);
		paramsMap.put("nonce_str", String.valueOf(new Date().getTime()));
		try {
			paramsMap.put("sign",getSign(paramsMap,sysPlugin));
		} catch (Exception e) {
			finalpackage.put("return_code", "9999");
			finalpackage.put("error_msg","签名出错");
			return finalpackage;
		}

		String reqUrl = "https://api.mch.weixin.qq.com/pay/refundquery";

		try {
			String xml = XMLUtils.mapToXml(paramsMap);
			HttpClient httpClient =	createSSLHttpClient(sysPlugin);
			String resultXml = post(reqUrl,xml,httpClient);
			HashMap<String,Object> resultMap = XMLUtils.xmlToMap(resultXml);
			if (resultMap.containsKey("sign")) {
				String sign = getSign(resultMap,sysPlugin);
				if(!sign.equals(resultMap.get("sign").toString())){
					finalpackage.put("return_code", "9999");
					finalpackage.put("result_msg","签名出错");
					return finalpackage;
				} else {
					if ("SUCCESS".equals(resultMap.get("return_code").toString()) && "SUCCESS".equals(resultMap.get("result_code").toString())) {
						int count = Integer.parseInt(resultMap.get("refund_count").toString())-1;
						if ("SUCCESS".equals(resultMap.get("refund_status_"+count).toString())) {
							finalpackage.put("return_code", "0000");
							finalpackage.put("error_msg","退款成功");
							finalpackage.put("tranSn", (String) resultMap.get("transaction_id"));
							return finalpackage;
						} else if ("PROCESSING".equals(resultMap.get("refund_status_"+count).toString())) {
							finalpackage.put("return_code", "0001");
							finalpackage.put("error_msg","退款处理中");
							return finalpackage;
						} else if ("REFUNDCLOSE".equals(resultMap.get("refund_status_"+count).toString())) {
							finalpackage.put("return_code", "0003");
							finalpackage.put("error_msg","退款失败");
							return finalpackage;
						} else if("CHANGE".equals(resultMap.get("refund_status_"+count).toString())){
							finalpackage.put("return_code", "0003");
							finalpackage.put("error_msg","退款失败");
							return finalpackage;
						} else {
							finalpackage.put("return_code", "9999");
							finalpackage.put("error_msg",resultMap.get("return_msg").toString());
							return finalpackage;
						}
					} else {
						finalpackage.put("return_code", "9999");
						finalpackage.put("error_msg",resultMap.get("err_code_des").toString());
						return finalpackage;
					}
				}
			} else {
				finalpackage.put("return_code", "9999");
				finalpackage.put("error_msg",resultMap.get("err_code_des").toString());
				return finalpackage;
			}

		} catch (Exception e) {
			finalpackage.put("return_code", "9999");
			finalpackage.put("error_msg",e.getMessage());
			return finalpackage;
		}

	}

}